home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Tech Arsenal 1
/
Tech Arsenal (Arsenal Computer).ISO
/
tek-13
/
dte5_1.zip
/
HWHPXL.C
< prev
next >
Wrap
C/C++ Source or Header
|
1991-02-06
|
50KB
|
1,589 lines
/*
* Written by Douglas Thomson (1989/1990)
*
* This source code is released into the public domain.
*/
/*
* Name: dte - Doug's Text Editor program - hardware dependent module
* Purpose: This file contains all the code that needs to be different on
* different hardware.
* File: hwhpxl.c (actually HWHPXLC due to naming restrictions)
* Author: Douglas Thomson
* System: This particular version is for the HP3000 running MPE/XL.
* Date: October 10, 1989
* Notes: This module has been kept as small as possible, to facilitate
* porting between different systems.
* This is a preliminary version, which does not support any
* way to find out whether a character has been typed without
* waiting for it. There seems to be no simple way to do this.
* I tried using NOWAIT I/O on $STDIN, but it seems that a
* pending read (even a NOWAIT read) prevents any further output
* to the terminal!!!
* Because of this, it is very important to use what HP call a
* type ahead engine. This is supplied in a file called:
* TYPE.DTS0000.TELESUP
* and the required command is:
* TYPE.DTS0000.TELESUP ON
* which enables type ahead for all subsequent programs. HP
* have some justification for not making this the default,
* but I confess I could not follow their logic.
* Without type ahead, "dte" loses keystrokes all over the place!
*/
#include "commonh" /* dte types */
#include "hwdeph" /* prototypes for functions here */
#include "utilsh" /* for displaying messages etc */
#include "versionh" /* current version number */
#include <mpe.h> /* access to MPE intrinsics */
#include <varargs.h> /* for passing variable numbers of parameters */
#include <fcntl.h> /* for open flags */
/*
* prototypes for all functions in this file
*/
static void myputchar ARGS((char c));
static void myputs ARGS((char *s));
void error ARGS((int kind, ...));
static void termset ARGS((char *name));
void main ARGS((int argc, char *argv[]));
static void hw_attr ARGS((char attr));
static void att_stuff ARGS((void));
void att_check ARGS((void));
void hw_xygoto ARGS((void));
int hw_clreol ARGS((void));
int hw_linedel ARGS((int line));
int hw_scroll_up ARGS((int top, int bottom));
int hw_lineins ARGS((int line));
int hw_scroll_down ARGS((int top, int bottom));
int hw_c_avail ARGS((void));
int hw_c_input ARGS((void));
void hw_c_output ARGS((int c));
void hw_terminate ARGS((void));
void hw_initialize ARGS((void));
void hw_move ARGS((text_ptr dest, text_ptr source, long number));
int hw_backspace ARGS((void));
int hw_c_insert ARGS((void));
int hw_c_delete ARGS((void));
int hw_rename ARGS((char *old, char *new));
int hw_fattrib ARGS((char *name));
int hw_set_fattrib ARGS((char *name, int attrib));
int hw_unlink ARGS((char *name));
int hw_printable ARGS((int c));
int hw_load ARGS((char *name, text_ptr start, text_ptr limit, text_ptr *end));
static int write_file ARGS((char *name, char *mode, text_ptr start,
text_ptr end));
int hw_save ARGS((char *name, text_ptr start, text_ptr end));
int hw_append ARGS((char *name, text_ptr start, text_ptr end));
int hw_print ARGS((text_ptr start, text_ptr end));
void hw_copy_path ARGS((char *old, char *name, char *new));
/*
* These pragmas provide access to system intrinsics necessary mainly
* for direct keyboard input.
*/
#pragma intrinsic COMMAND MPE_COMMAND
#pragma intrinsic FFILEINFO MPE_FFILEINFO
#pragma intrinsic FCONTROL MPE_FCONTROL
#pragma intrinsic FDEVICECONTROL MPE_FDEVICECONTROL
#pragma intrinsic FREAD MPE_FREAD
#pragma intrinsic FWRITE MPE_FWRITE
#pragma intrinsic FRENAME MPE_FRENAME
#pragma intrinsic HPCIPUTVAR MPE_PUTVAR
#define REVERSE 1 /* reverse video (or standout) attribute */
#define HIGH 2 /* high intensity (or underline) attribute */
#define NORMAL 3 /* normal video attribute */
/*
* The following variables store the appropriate escape sequences for
* the current terminal type. This is not very elegant coding, although
* the problem with global variables is at least restricted to just this
* one source file.
* Eventually it would be nice to implement some equivalent to a UNIX
* termcap file...
*/
static char *t_flash1; /* start flash attribute */
static char *t_flash0; /* end flash attribute */
static char *t_block1; /* start block attribute */
static char *t_block0; /* end block attribute */
static char *t_eol; /* erase to end of line */
static char *t_insline; /* insert line */
static char *t_delline; /* delete line */
static char *t_inschar; /* insert character */
static char *t_delchar; /* delete character */
static char *t_defwind; /* define scrollable window */
static char *t_scrup; /* scroll window up */
static char *t_scrdown; /* scroll window down */
static char *t_cp; /* cursor positioning */
static int t_cpoff; /* cursor positioning offset */
static int t_hptinit; /* set up HP (700/41) terminal function keys? */
/*
* Under MPE/XL, text files can either have variable length lines or fixed
* length lines. For most purposes (such as program source files) using
* variable length lines saves wasting space. However, MPE/XL insists that
* job files have fixed length lines. Therefore, the editor must be able to
* create either kind of file.
* This is achieved by checking the name of the executing program: DTE implies
* variable length lines, DTEJ implies fixed length lines.
* The "g_job_file" variable is set TRUE if we are working with job files.
*/
int g_job_file;
/*
* the following variable determines the size of the memory buffer used. It
* is set to something reasonable in main.
*/
static int g_space = 0;
/*
* Name: myfflush
* Purpose: To flush any pending characters in the output buffer.
* Date: September 3, 1990
*/
static void myfflush()
{
fflush(stdout);
}
/*
* Name: myputchar
* Purpose: To output a single character to the display device.
* Date: September 3, 1990
* Passed: c: the character to be output
*/
static void myputchar(c)
char c;
{
putc(c, stdout);
}
/*
* Name: myputs
* Purpose: To output a character string to the display device.
* Date: November 6, 1989
* Passed: s: the character string to be output
*/
static void myputs(s)
char *s;
{
while (*s) {
myputchar(*s++);
}
}
/*
* Name: error
* Purpose: To report an error, and usually make the user type <ESC> before
* continuing.
* Date: October 10, 1989
* Passed: kind: an indication of how serious the error was:
* TEMP: merely a message, do not wait for <ESC>
* DIAG: merely a message, but make sure user sees it
* WARNING: error, but editor can continue after <ESC>
* FATAL: abort the editor!
* format: printf format string for any arguments that follow
* ...: arguments to be printed
* Notes: This function should be system independent; that is the whole
* point of the "stdarg" philosophy. However, two of the systems
* I have used implemented "stdarg" incompatibly, and some older
* systems may not support the "stdarg" macros at all...
*/
void error(kind, va_alist)
int kind;
va_dcl
{
char *format; /* printf format string for error message */
va_list argptr; /* used to access various arguments */
char buff[MAX_COLS]; /* somewhere to store error before printing */
int c; /* character entered by user to continue */
/*
* obtain the first two arguments
*/
va_start(argptr);
format = va_arg(argptr, char *);
/*
* tell the user what kind of an error it is
*/
switch (kind) {
case FATAL:
strcpy(buff, "Fatal error: ");
break;
case WARNING:
strcpy(buff, "Warning: ");
break;
case DIAG:
case TEMP:
strcpy(buff, "");
break;
}
/*
* prepare the error message itself
*/
vsprintf(buff + strlen(buff), format, argptr);
va_end(argptr);
/*
* tell the user how to continue editing if necessary
*/
if (kind == WARNING || kind == DIAG) {
strcat(buff, ": type <ESC>");
}
/*
* output the error message
*/
set_prompt(buff, 1);
if (kind == FATAL) {
/*
* no point in making the user type <ESC>, since the program is
* about to abort anyway...
*/
terminate();
exit(1);
}
else if (kind != TEMP) {
/*
* If necessary, force the user to acknowledge the error by
* typing <ESC> (or ^U).
* This prevents any extra commands the user has entered from
* causing problems after an error may have made them inappropriate.
*/
while ((c=c_input()) != 27 && c != CONTROL('U')) {
set_prompt(buff, 1);
}
}
}
/*
* Name: termset
* Purpose: To set an MPE variable to record the terminal type for future
* invocations of the editor.
* Passed: name: the name of the terminal (termcap style!)
* Date: November 10, 1989
*/
static void termset(name)
char *name;
{
int length; /* length of terminal name */
int status; /* status of MPE variable setting command */
length = strlen(name);
MPE_PUTVAR("DTETERM", &status, 2, name, 11, &length);
}
/*
* Name: main
* Purpose: To do any system dependent command line argument processing,
* and then call the main editor function.
* Date: November 10, 1989
* Passed: argc: number of command line arguments
* argv: text of command line arguments
* Notes: The MPE/XL version needs to determine the type of terminal
* currently in use.
*/
void main(argc, argv)
int argc;
char *argv[];
{
char termc; /* terminal identifier */
char *term; /* terminal name */
static char std_buff[4096]; /* output buffer */
/*
* allocate a large output buffer
*/
setvbuf(stdout, std_buff, _IOFBF, 4096);
/*
* work out whether we are working with job files or normal files.
*/
if (mystrcmpi("DTEJ", argv[0]) == 0) {
g_job_file = TRUE;
}
else {
g_job_file = FALSE;
}
/*
* see if user specified buffer size
*/
if (argc > 1 && mystrcmpi("-s", argv[1]) == 0) {
g_space = atoi(argv[1]+2);
++argv;
--argc;
}
/*
* ensure space is reasonable
*/
if (g_space < 1000) {
g_space = 100000; /* enough for program source code files */
}
/*
* set path for the help file
*/
hw_copy_path(argv[0], "DTEHELP", g_status.help_file);
/*
* Check DTETERM system variable to see if a terminal kind has already
* been set.
*/
termc = '?';
if ((term = getenv("DTETERM")) != NULL) {
if (strcmp(term, "vt100") == 0) {
termc = 'v';
}
else if (strcmp(term, "vt220") == 0) {
termc = '2';
}
else if (strcmp(term, "tvi920") == 0) {
termc = 't';
}
else if (strcmp(term, "tvi925") == 0) {
termc = 'h';
}
else if (strcmp(term, "hp2392a") == 0) {
termc = '9';
}
else if (strcmp(term, "dmp") == 0) {
termc = 'd';
}
}
/*
* If no system variable, then ask the user to choose from a menu
* of supported terminals.
*/
if (termc == '?') {
for (;;) {
myputs("Terminals Available:\n\n");
myputs(" v) VT100 (VISUAL 300)\n");
myputs(" 2) VT220\n");
myputs(" h) Televideo 925 (HP700/41)\n");
myputs(" 9) HP 2392A\n");
myputs(" t) Televideo 920 (PROCOMM)\n");
myputs(" d) DMP\n\n");
myputs("Selection: ");
myfflush();
switch (getchar()) {
case 'v':
case 'V':
termc = 'v';
termset("vt100");
break;
case '2':
termc = '2';
termset("vt220");
break;
case 'h':
case 'H':
termc = 'h';
termset("tvi925");
break;
case 't':
case 'T':
termc = 't';
termset("tvi920");
break;
case '9':
termc = '9';
termset("hp2392a");
break;
case 'd':
termc = 'd';
termset("dmp");
break;
default:
fflush(stdin);
continue;
}
break;
}
}
/*
* now terminal type is known, set the appropriate escape sequences
*/
switch (termc) {
case 'v':
t_flash1 = "\033[1m"; /* start flash attribute */
t_flash0 = "\033[m"; /* end flash attribute */
t_block1 = "\033[7m"; /* start block attribute */
t_block0 = "\033[m"; /* end block attribute */
t_eol = "\033[K"; /* erase to end of line */
t_insline = NULL; /* insert line */
t_delline = NULL; /* delete line */
t_inschar = NULL; /* insert character */
t_delchar = NULL; /* delete character */
t_defwind = "\033[%d;%dr"; /* define scrollable window */
t_scrup = "\033M"; /* scroll window up */
t_scrdown = "\n"; /* scroll window down */
t_cp = "\033[%d;%dH"; /* cursor positioning */
t_cpoff = 1; /* cursor positioning offset */
break;
case '2':
t_flash1 = "\033[1m"; /* start flash attribute */
t_flash0 = "\033[m"; /* end flash attribute */
t_block1 = "\033[7m"; /* start block attribute */
t_block0 = "\033[m"; /* end block attribute */
t_eol = "\033[K"; /* erase to end of line */
t_insline = "\033[L"; /* insert line */
t_delline = "\033[M"; /* delete line */
t_inschar = NULL; /* insert character */
t_delchar = "\033[P"; /* delete character */
t_defwind = "\033[%d;%dr"; /* define scrollable window */
t_scrup = "\033M"; /* scroll window up */
t_scrdown = "\033D"; /* scroll window down */
t_cp = "\033[%d;%dH"; /* cursor positioning */
t_cpoff = 1; /* cursor positioning offset */
break;
case 'h':
t_flash1 = NULL; /* start flash attribute */
t_flash0 = NULL; /* end flash attribute */
t_block1 = NULL; /* start block attribute */
t_block0 = NULL; /* end block attribute */
t_eol = "\033T"; /* erase to end of line */
t_insline = "\033E"; /* insert line */
t_delline = "\033R"; /* delete line */
t_inschar = "\033Q"; /* insert character */
t_delchar = "\033W"; /* delete character */
t_defwind = NULL; /* define scrollable window */
t_scrup = NULL; /* scroll window up */
t_scrdown = NULL; /* scroll window down */
t_cp = "\033=%c%c"; /* cursor positioning */
t_cpoff = 32; /* cursor positioning offset */
t_hptinit = TRUE; /* initialize terminal keys */
break;
case 't':
t_flash1 = "\033l"; /* start flash attribute */
t_flash0 = "\033m"; /* end flash attribute */
t_block1 = "\033j"; /* start block attribute */
t_block0 = "\033k"; /* end block attribute */
t_eol = "\033T"; /* erase to end of line */
t_insline = "\033E"; /* insert line */
t_delline = "\033R"; /* delete line */
t_inschar = "\033Q"; /* insert character */
t_delchar = "\033W"; /* delete character */
t_defwind = NULL; /* define scrollable window */
t_scrup = NULL; /* scroll window up */
t_scrdown = NULL; /* scroll window down */
t_cp = "\033=%c%c"; /* cursor positioning */
t_cpoff = 32; /* cursor positioning offset */
break;
case '9':
t_flash1 = NULL; /* start flash attribute */
t_flash0 = NULL; /* end flash attribute */
t_block1 = NULL; /* start block attribute */
t_block0 = NULL; /* end block attribute */
t_eol = "\033K"; /* erase to end of line */
t_insline = "\033L"; /* insert line */
t_delline = "\033M"; /* delete line */
t_inschar = NULL; /* insert character */
t_delchar = "\033P"; /* delete character */
t_defwind = NULL; /* define scrollable window */
t_scrup = NULL; /* scroll window up */
t_scrdown = NULL; /* scroll window down */
t_cp = "\033&a%dy%dC"; /* cursor positioning */
t_cpoff = 0; /* cursor positioning offset */
break;
case 'd':
t_flash1 = "\020"; /* start flash attribute */
t_flash0 = "\016"; /* end flash attribute */
t_block1 = "\022"; /* start block attribute */
t_block0 = "\016"; /* end block attribute */
t_eol = "\027"; /* erase to end of line */
t_insline = "\030"; /* insert line */
t_delline = "\031"; /* delete line */
t_inschar = "\025"; /* insert character */
t_delchar = "\026"; /* delete character */
t_defwind = "\013%c%c"; /* define scrollable window */
t_scrup = "\005"; /* scroll window up */
t_scrdown = "\006"; /* scroll window down */
t_cp = "\002%c%c"; /* cursor positioning */
t_cpoff = 32; /* cursor positioning offset */
break;
}
/*
* now start up the main editor
*/
editor(argc, argv);
}
/*
* Name: hw_attr
* Purpose: To select a new attribute on the terminal.
* Date: October 10, 1989
* Passed: attr: the desired attribute
*/
static void hw_attr(attr)
char attr;
{
static int old_att = -1; /* existing attribute */
/*
* If there has been no change, then ignore the call (actually this
* should never happen, since hw_attr is only called when the
* attribute HAS changed...
*/
if (old_att == attr) {
return;
}
/*
* end the current attribute
*/
if (old_att != g_display.normal) {
if (old_att == g_display.flash) {
if (t_flash0) {
myputs(t_flash0);
}
}
else if (old_att == g_display.block) {
if (t_block0) {
myputs(t_block0);
}
}
}
/*
* set the new attribute
*/
if (attr == g_display.flash) {
if (t_flash1) {
myputs(t_flash1);
}
}
else if (attr == g_display.block) {
if (t_block1) {
myputs(t_block1);
}
}
/*
* record new attribute for next time
*/
old_att = attr;
}
/*
* Name: att_stuff
* Purpose: To make sure that the attribute is set to normal before commands
* such as clear to end of line are executed.
* Date: October 10, 1989
* Passed: [g_display.attr]: the current attribute
* [g_display.normal]: the normal attribute
* Returns: [g_display.attr]: set to normal
* Notes: This function is necessary because some terminals clear to
* spaces using the current attribute, while others clear to
* normal spaces. Unfortunately terminfo does not seem to record
* this distinction.
*/
static void att_stuff()
{
if (g_display.attr != g_display.normal) {
hw_attr(g_display.normal);
g_display.attr = g_display.normal;
}
}
/*
* Name: att_check
* Purpose: To check that the attribute required for the next character is
* the one currently in effect, and set it if different.
* Date: October 10, 1989
* Passed: [g_display.attr]: the current attribute
* [g_status.wanted]: the required attribute
* Returns: [g_display.attr]: the newly set attribute
*/
void att_check()
{
if (g_display.attr != g_status.wanted) {
hw_attr(g_status.wanted);
g_display.attr = g_status.wanted;
}
}
/*
* Name: hw_xygoto
* Purpose: To move the cursor to a new position on the screen.
* Date: October 10, 1989
* Passed: [g_display.line]: the required line
* [g_display.col]: the required column
*/
void hw_xygoto()
{
char buff[20]; /* for cursor positioning command */
sprintf(buff, t_cp, g_display.line+t_cpoff, g_display.col+t_cpoff);
myputs(buff);
}
/*
* The following locally global variables are used to keep track of the
* character in the bottom right corner of the screen.
* It is not safe to write this character, since most terminals will
* scroll the whole screen up a line after writing it.
* However, if the screen is subsequently scrolled up for any reason, then
* this character must appear on the second bottom line!
* This causes numerous complications in the code which follows...
*/
static char g_mem_c = 0; /* character supposed to be at bottom right */
static char g_mem_attr; /* attribute for g_mem_c */
/*
* Name: hw_clreol
* Purpose: To clear from the cursor to the end of the cursor line.
* Date: October 10, 1989
* Returns: TRUE if the hardware could clear to end of line, FALSE otherwise
*/
int hw_clreol()
{
/*
* find out if function is available, and give up if not
*/
if (t_eol == NULL) {
return FALSE;
}
/*
* clear to end of line, using normal attribute
*/
att_stuff();
myputs(t_eol);
/*
* If we just cleared the bottom line, then the bottom right character
* was cleared too.
*/
if (g_display.line == g_display.nlines-1) {
g_mem_c = 0;
}
return TRUE;
}
/*
* Name: hw_linedel
* Purpose: To delete the cursor line, scrolling lines below up.
* Date: October 10, 1989
* Passed: line: line on screen to be deleted
* Returns: TRUE if the hardware could delete the line, FALSE otherwise
*/
int hw_linedel(line)
int line;
{
/*
* check availability of function
*/
if (t_delline == NULL) {
return FALSE;
}
/*
* delete the line
*/
att_stuff();
xygoto(0, line);
myputs(t_delline);
/*
* If this caused the bottom line to move up (which will usually be
* the case), then add the bottom right character (if any) onto the
* second bottom line.
*/
if (g_mem_c) {
if (line < g_display.nlines-1) {
xygoto(g_display.ncols-1, g_display.nlines-2);
set_attr(g_mem_attr);
c_output(g_mem_c);
g_display.col = g_display.line = -1;
}
g_mem_c = 0;
}
return TRUE;
}
/*
* Name: hw_scroll_up
* Purpose: To scroll the lines in a given region up one line.
* Date: October 10, 1989
* Passed: top: the top line in the window
* bottom: the bottom line in the window
* Returns: TRUE if terminal could scroll, FALSE otherwise
* Notes: If this function does not exist, then insert and delete line
* can achieve the same effect. However, insert and delete line
* make lower windows jump, so using terminal scrolling is
* preferable.
*/
int hw_scroll_up(top, bottom)
int top;
int bottom;
{
char buff[20]; /* for window definition command */
/*
* check if function is available
*/
if (t_defwind == NULL || t_scrdown == NULL) {
return FALSE;
}
/*
* select window to be affected
*/
att_stuff();
sprintf(buff, t_defwind, top+t_cpoff, bottom+t_cpoff);
myputs(buff);
g_display.col = -1;
g_display.line = -1;
/*
* scroll the window up
*/
xygoto(0, bottom);
myputs(t_scrdown);
/*
* don't leave a peculiar region scrolling - it confuses all sorts of
* things!
*/
sprintf(buff, t_defwind, 0+t_cpoff, g_display.nlines-1+t_cpoff);
myputs(buff);
g_display.col = -1;
g_display.line = -1;
/*
* if the bottom line was scrolled up, then restore the old bottom
* right character to the second bottom line
*/
if (g_mem_c) {
if (bottom == g_display.nlines-1) {
xygoto(g_display.ncols-1, g_display.nlines-2);
set_attr(g_mem_attr);
c_output(g_mem_c);
g_display.col = -1;
g_display.line = -1;
}
g_mem_c = 0;
}
return TRUE;
}
/*
* Name: hw_lineins
* Purpose: To insert a blank line above the cursor line, scrolling the
* cursor line and lines below down.
* Date: October 10, 1989
* Passed: line: line on screen to be inserted
* Returns: TRUE if the hardware could insert the line, FALSE otherwise
*/
int hw_lineins(line)
int line;
{
/*
* give up if not available
*/
if (t_insline == NULL) {
return FALSE;
}
/*
* insert the line
*/
att_stuff();
xygoto(0, line);
myputs(t_insline);
/*
* regardless of where the line was inserted, the bottom line
* (including the bottom right character) scrolled off the screen
*/
g_mem_c = 0;
return TRUE;
}
/*
* Name: hw_scroll_down
* Purpose: To scroll the lines in a given region down one line.
* Date: October 10, 1989
* Passed: top: the top line in the window
* bottom: the bottom line in the window
* Returns: TRUE if terminal could scroll, FALSE otherwise
* Notes: If this function does not exist, then insert and delete line
* can achieve the same effect. However, insert and delete line
* make lower windows jump, so using terminal scrolling is
* preferable.
*/
int hw_scroll_down(top, bottom)
int top;
int bottom;
{
char buff[20]; /* for define window command */
/*
* check if function is available
*/
if (t_defwind == NULL || t_scrup == NULL) {
return FALSE;
}
/*
* select window to be affected
*/
att_stuff();
sprintf(buff, t_defwind, top+t_cpoff, bottom+t_cpoff);
myputs(buff);
g_display.col = -1;
g_display.line = -1;
/*
* scroll the window up
*/
xygoto(0, top);
myputs(t_scrup);
/*
* don't leave a peculiar region scrolling - it confuses all sorts of
* things!
*/
sprintf(buff, t_defwind, 0+t_cpoff, g_display.nlines-1+t_cpoff);
myputs(buff);
g_display.col = -1;
g_display.line = -1;
/*
* if the region included the bottom line, then the bottom right
* character moved off the screen altogether
*/
if (bottom == g_display.nlines-1) {
g_mem_c = 0;
}
return TRUE;
}
/*
* Name: hw_c_avail
* Purpose: To test whether or not a character has been typed by the user.
* Date: October 10, 1989
* Returns: TRUE if user typed something, FALSE otherwise
* Notes: No simple way to check under MPE/XL, so just pretend the
* user waited until the screen was fully updated.
*/
int hw_c_avail()
{
return FALSE;
}
/*
* Name: hw_c_input
* Purpose: To input a character from the user, without echo, waiting if
* nothing has been typed yet.
* Date: October 10, 1989
* Returns: the character the user typed
* Notes: A return value of 0 means that what the user typed should be
* ignored.
*/
int hw_c_input()
{
char key; /* the key the user typed */
myfflush(); /* first display everything that is pending */
MPE_FREAD(_mpe_fileno(0), &key, -1);
return key;
}
/*
* Name: hw_c_output
* Purpose: To output a character, using the current attribute, at the
* current screen position.
* Date: October 10, 1989
* Notes: If the current screen position is the bottom right corner, then
* we do not write the character, but merely store it away for
* later. (See explanation above.)
*/
void hw_c_output(c)
int c;
{
if (g_display.line == g_display.nlines-1 &&
g_display.col == g_display.ncols-1) {
g_mem_c = c;
g_mem_attr = g_status.wanted;
return;
}
att_check();
myputchar(c);
}
/*
* Name: hw_terminate
* Purpose: To restore the terminal to a safe state prior to leaving the
* editor.
* Date: October 10, 1989
*/
void hw_terminate()
{
unsigned short status; /* error status of MPE intrinsic */
unsigned short command; /* device control command number */
/*
* ensure no windows are left (it is annoying to exit the editor and
* then find that only the bottom 4 lines of the screen can be used
* for other purposes!
*/
window_scroll_up(0, g_display.nlines-1);
/*
* leave the editor text on the screen, but move the cursor to the
* bottom line.
*/
xygoto(0, g_display.nlines-1);
att_stuff();
/*
* restore text mode with echo
*/
command = 1;
MPE_FDEVICECONTROL(_mpe_fileno(0), &command, 1, 192, 26, 2, &status);
command = 0;
MPE_FDEVICECONTROL(_mpe_fileno(0), &command, 1, 192, 32, 2, &status);
MPE_FCONTROL(_mpe_fileno(0), 12, &status);
MPE_FCONTROL(_mpe_fileno(0), 26, &status);
MPE_FCONTROL(_mpe_fileno(0), 15, &status);
printf("dte version %sC for MPE/XL %s files\n", VERSION,
g_job_file ? "job" : "program");
}
/*
* If the MPE/XL C library contained a function to do overlapping moves
* correctly, then only one text buffer would be required. However,
* copying individual bytes was too slow, and it was much faster to
* copy everything to an extra buffer, and then back to the destination!
*/
static char *g_buffer;
/*
* Name: hw_initialize
* Purpose: To initialize the display ready for editor use.
* Date: October 10, 1989
* Notes: Typed characters (including ^S and ^Q and ^\) must all be
* returned without echoing!
*/
void hw_initialize()
{
unsigned short result; /* result of setting up terminal commands */
unsigned short command; /* MPE device control command number */
char buff[20]; /* for cursor positioning command */
/*
* allocate space for the screen image
*/
if ((g_screen = (screen_lines *)malloc(MAX_LINES * sizeof(screen_lines)))
== NULL) {
printf("no memory for screen image\n");
exit(1);
}
/*
* set up terminal screen size
*/
g_display.ncols = 80;
g_display.nlines = 24;
/*
* work out the length of the cursor addressing command, so we can
* choose the quickest way of getting anywhere
*/
sprintf(buff, t_cp, 24+t_cpoff, 80+t_cpoff);
g_display.ca_len = strlen(buff);
/*
* set up raw input with no echo etc
*/
MPE_FCONTROL(_mpe_fileno(0), 13, &result);
MPE_FCONTROL(_mpe_fileno(0), 14, &result);
command = 0;
MPE_FDEVICECONTROL(_mpe_fileno(0), &command, 1, 192, 26, 2, &result);
command = 0;
MPE_FDEVICECONTROL(_mpe_fileno(0), &command, 1, 192, 32, 2, &result);
MPE_FCONTROL(_mpe_fileno(0), 27, &result);
/*
* set up video attributes
*/
g_display.block = REVERSE;
g_display.flash = HIGH;
g_display.normal = NORMAL;
g_display.attr = NORMAL;
hw_attr(NORMAL);
if (t_hptinit) {
/*
* initialize function keys, select terminal emulation
*/
printf("\033~\"\033~ ");
printf("\033z#%c\177", CONTROL('G'));
printf("\033z&%c\177", CONTROL('I'));
printf("\033z+%c\177", CONTROL('E'));
printf("\033z,%c\177", CONTROL('X'));
printf("\033z-%c\177", CONTROL('S'));
printf("\033z.%c\177", CONTROL('D'));
printf("\033z/%c%c\177", CONTROL('Q'), CONTROL('E'));
printf("\033~$\033\"\033'");
fflush(stdout);
}
/*
* allocate space for the main text buffer and the copying buffer
*/
if ((g_status.start_mem = (char *)malloc(g_space)) == NULL) {
error(FATAL, "out of memory for text");
}
g_status.max_mem = g_status.start_mem + g_space;
if ((g_buffer = (char *)malloc(g_space)) == NULL) {
error(FATAL, "out of memory for buffer");
}
}
/*
* Name: hw_move
* Purpose: To move data from one place to another as efficiently as
* possible.
* Date: October 10, 1989
* Passed: dest: where to copy to
* source: where to copy from
* number: number of bytes to copy
* Notes: moves may be (usually will be) overlapped
*/
void hw_move(dest, source, number)
text_ptr dest;
text_ptr source;
long number;
{
if (number < 0) {
/*
* this should never happen...
*/
error(WARNING, "negative move - contact Douglas Thomson!");
}
else if (source == dest) {
/*
* nothing to be done
*/
;
}
else {
/*
* no overlapping move available, so copy to buffer and back
*/
memcpy(g_buffer, source, number);
memcpy(dest, g_buffer, number);
}
}
/*
* Name: hw_backspace
* Purpose: To move the cursor left one position.
* Date: October 10, 1989
* Returns: TRUE if the hardware could backspace, FALSE otherwise
* Notes: This function is used where deletion requires a backspace,
* space, backspace. If the terminal can backspace, this may
* be much faster than using cursor addressing.
*/
int hw_backspace()
{
myputchar('\b');
return TRUE;
}
/*
* Name: hw_c_insert
* Purpose: To insert a blank character under the cursor.
* Date: October 10, 1989
* Returns: TRUE if the hardware could insert the space, FALSE otherwise
* Notes: This function is used where the user has just typed a character
* in the middle of a line in insert mode. If it is available, it
* saves having to redraw the entire remainder of the line.
* No assumptions are made about the contents or attribute of the
* inserted character.
*/
int hw_c_insert()
{
if (t_inschar == NULL) {
return FALSE;
}
myputs(t_inschar);
if (g_mem_c && g_display.line == g_display.nlines-1) {
g_mem_c = 0;
}
return TRUE;
}
/*
* Name: hw_c_delete
* Purpose: To delete the character under the cursor.
* Date: October 10, 1989
* Returns: TRUE if the hardware could delete the character, FALSE otherwise
* Notes: This function is used where the user has deleted a character
* in the middle of a line. If it is available, it saves having to
* redraw the entire remainder of the line.
* The rightmost character on the line after the delete is assumed
* to be a space character with normal attribute.
*/
int hw_c_delete()
{
if (t_delchar == NULL) {
return FALSE;
}
myputs(t_delchar);
/*
* bottom right corner character could need to reappear one
* character in from the right
*/
if (g_mem_c && g_display.line == g_display.nlines-1) {
if (g_display.col < g_display.ncols-2) {
xygoto(g_display.ncols-2, g_display.nlines-1);
set_attr(g_mem_attr);
c_output(g_mem_c);
g_display.col = g_display.line = -1;
}
g_mem_c = 0;
}
return TRUE;
}
/*
* Name: hw_rename
* Purpose: To rename a disk file to a new name.
* Date: October 10, 1989
* Passed: old: current file name
* new: new desired file name
* Returns: OK if rename succeeded, ERROR if any problem
*/
int hw_rename(old, new)
char *old;
char *new;
{
return rename(old, new);
}
/*
* Name: hw_fattrib
* Purpose: To determine the current file attributes.
* Date: October 17, 1989
* Passed: name: name of file to be checked
* Returns: current read/write/execute etc attributes of the file, or
* ERROR if file did not exist etc.
*/
int hw_fattrib(name)
char *name;
{
FILE *fp;
/*
* The MPE/XL implementation is very simple-minded.
*/
if ((fp = fopen(name, "r")) == NULL) {
return ERROR;
}
fclose(fp);
return OK;
}
/*
* Name: hw_set_fattrib
* Purpose: To set the current file attributes.
* Date: October 17, 1989
* Passed: name: name of file to be changed
* attrib: the required attributes
* Returns: new read/write/execute etc attributes of the file, or
* ERROR if file did not exist etc.
* Notes: If "attrib" is ERROR, then do not change attributes.
*/
int hw_set_fattrib(name, attrib)
char *name;
int attrib;
{
if (attrib == ERROR) {
return ERROR;
}
return OK;
}
/*
* Name: hw_unlink
* Purpose: To delete a file, regardless of access modes.
* Date: October 17, 1989
* Passed: name: name of file to be removed
* Returns: OK if file could be removed
* ERROR otherwise
*/
int hw_unlink(name)
char *name;
{
FILE *fp;
/*
* Open file in such a way that it will be removed when closed -
* seems an odd way to do things, but the MPE/XL library
* has no unlink().
*/
if ((fp = fopen(name, "r Df4")) == NULL) {
return ERROR;
}
return fclose(fp);
}
/*
* Name: hw_printable
* Purpose: To determine whether or not a character is printable on the
* current hardware.
* Date: October 18, 1989
* Passed: c: the character to be tested
* Returns: TRUE if c is a visible character, FALSE otherwise
* Notes: This is hardware dependent so that machines like the IBM PC can
* edit files containing graphics characters.
*/
int hw_printable(c)
int c;
{
return (c >= 32 && c < 127);
}
/*
* Name: hw_load
* Purpose: To load a file into the text buffer.
* Date: November 11, 1989
* Passed: name: name of disk file
* start: first character in text buffer
* limit: last available character in text buffer
* end: last character (+1) from the file
* Returns: OK, or ERROR if anything went wrong
* Notes: All error messages are displayed here, so the caller should
* neither tell the user what is happening, nor print an error
* message if anything goes wrong.
* This function is in the hardware dependent module because
* some computers require non-standard open parameters...
*/
int hw_load(name, start, limit, end)
char *name;
text_ptr start;
text_ptr limit;
text_ptr *end;
{
int fd; /* file being read */
int length; /* number of bytes actually read */
short code; /* file type code */
foptions foption; /* for determining if file is ASCII */
/*
* try reading the file, trimming trailing space and editor line
* numbers.
*/
if ((fd = open(name, O_RDONLY|O_MPEOPTS, 0, "Tm")) == ERROR) {
error(WARNING, "File '%s' not found", name);
return ERROR;
}
/*
* check file is ASCII text file
*/
code = -1;
MPE_FFILEINFO(_mpe_fileno(fd), 8, &code);
if (code != 0) {
close(fd);
error(WARNING, "cannot edit this file type (%d)", code);
return ERROR;
}
foption.fs.ascii = 0;
MPE_FFILEINFO(_mpe_fileno(fd), 2, &foption.fv);
if (foption.fs.ascii != 1) {
close(fd);
error(WARNING, "only ASCII text files can be edited");
return ERROR;
}
/*
* tell the user what is happening
*/
error(TEMP, "Reading file '%s'...", name);
/*
* read the entire file, without going past end of buffer.
* Note that this means a file that is within 1K of the limit
* will not be accepted.
*/
limit -= 1024;
for (;;) {
if (start >= limit) {
error(WARNING, "file '%s' too big", name);
close(fd);
return ERROR;
}
if ((length = read(fd, (char *)start, 1024)) == ERROR) {
error(WARNING, "could not read file '%s'", name);
close(fd);
return ERROR;
}
start += length;
if (length == 0) {
/*
* we reached the end of file
*/
break;
}
}
/*
* close the file and report the final character in the buffer
*/
close(fd);
*end = start;
return OK;
}
/*
* Name: write_file
* Purpose: To write text to a file, eliminating trailing space on the
* way.
* Date: November 11, 1989
* Passed: name: name of disk file or device
* mode: fopen flags to be used in open
* start: first character in text buffer
* end: last character (+1) in text buffer
* Returns: OK, or ERROR if anything went wrong
* Notes: Trailing space at the very end of the text is NOT removed,
* so that a block write of a block of spaces will work.
* No error messages are displayed here, so the caller must
* both tell the user what is happening, and print an error
* message if anything goes wrong.
* This function is in the hardware dependent module because
* some computers require non-standard open parameters...
*/
static int write_file(name, mode, start, end)
char *name;
char *mode;
text_ptr start;
text_ptr end;
{
FILE *fp; /* file to be written */
int spaces; /* no. of space characters pending */
char c; /* current character in file */
/*
* create a new file, or truncate an old one
*/
if ((fp = fopen(name, mode)) == NULL) {
return ERROR;
}
/*
* save the file, eliminating trailing space
*/
spaces = 0;
for (;;) {
if (start == end) {
break;
}
if ((c = *start++) == ' ') {
spaces++; /* count them, maybe output later */
continue;
}
if (c == '\n') {
spaces = 0; /* eliminate the trailing space */
}
else if (spaces) {
/*
* the spaces were NOT trailing, so output them now
*/
do {
if (putc(' ', fp) == ERROR) {
fclose(fp);
return ERROR;
}
} while (--spaces);
}
if (putc(c, fp) == ERROR) {
fclose(fp);
return ERROR;
}
}
/*
* output any trailing space at end of file - this may be important
* for block writes.
*/
if (spaces) {
do {
if (putc(' ', fp) == ERROR) {
fclose(fp);
return ERROR;
}
} while (--spaces);
}
return fclose(fp);
}
/*
* Name: hw_save
* Purpose: To save text to a file, eliminating trailing space on the
* way.
* Date: November 11, 1989
* Passed: name: name of disk file
* start: first character in text buffer
* end: last character (+1) in text buffer
* Returns: OK, or ERROR if anything went wrong
* Notes: Trailing space at the very end of the file is NOT removed,
* so that a block write of a block of spaces will work.
* No error messages are displayed here, so the caller must
* both tell the user what is happening, and print an error
* message if anything goes wrong.
* This function is in the hardware dependent module because
* some computers require non-standard open parameters...
*/
int hw_save(name, start, end)
char *name;
text_ptr start;
text_ptr end;
{
return write_file(name, g_job_file ? "w Ds1 R80" : "w Ds1 V", start, end);
}
/*
* Name: hw_append
* Purpose: To append text to a file.
* Date: November 11, 1989
* Passed: name: name of disk file
* start: first character in text buffer
* end: last character (+1) in text buffer
* Returns: OK, or ERROR if anything went wrong
* Notes: No error messages are displayed here, so the caller must
* both tell the user what is happening, and print an error
* message if anything goes wrong.
* This function is in the hardware dependent module because
* some computers require non-standard open parameters...
*/
int hw_append(name, start, end)
char *name;
text_ptr start;
text_ptr end;
{
return write_file(name, "a Ds1", start, end);
}
/*
* Name: hw_print
* Purpose: To print text to a printer.
* Date: November 11, 1989
* Passed: start: first character in text buffer
* end: last character (+1) in text buffer
* Returns: OK, or ERROR if anything went wrong
* Notes: This function is in the hardware dependent module because
* some computers require non-standard open parameters...
*/
int hw_print(start, end)
text_ptr start;
text_ptr end;
{
char command[300]; /* printer device command */
char *device; /* printer device name */
unsigned short status; /* printer file equation status */
unsigned short param; /* more info about any error */
/*
* work out where to print
*/
for (;;) {
strcpy(command, "2");
if (get_name("Printer 1N208 (1), 2S125 (2), Computer Center (3): ",
1, command) != OK) {
return ERROR;
}
switch (atoi(command)) {
case 1:
device = "300";
break;
case 2:
device = "309";
break;
case 3:
device = "6";
break;
default:
continue;
}
break;
}
sprintf(command, "FILE LP;DEV=%s\r", device);
MPE_COMMAND(command, &status, ¶m);
if (status) {
error(WARNING, "File equation error %d/%d", status, param);
return ERROR;
}
/*
* print file
*/
return write_file("LP", "a Ds1", start, end);
}
/*
* Name: hw_copy_path
* Purpose: To create a new file path using most of an old path but
* changing just the file name.
* Date: November 8, 1989
* Passed: old: the file path to extract path info from
* name: the file name to add to the extracted path info
* Returns: new: the new path
* Notes: The file is located in the same place as the original, so
* that related editor files stay in the same directory.
* This function is hardware dependent because different characters
* delimit directories on different systems.
*/
void hw_copy_path(old, name, new)
char *old;
char *name;
char *new;
{
char *cp; /* cutoff point in old path */
strcpy(new, name);
if ((cp = strchr(old, '.')) != NULL) {
strcat(new, cp);
}
}
/*
* Name: hw_os_shell
* Purpose: To shell out of the editor into the operating system, in such a
* way that editing may be resumed later.
* Date: November 28, 1990
* Returns: TRUE if screen may have been clobbered, FALSE if screen OK.
*/
int hw_os_shell()
{
return FALSE; /* not implemented - possible for unpriviledged users? */
}